using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace PS.WebParts.Rollup.Custom.UI.WebControls.WebParts
{
    [ToolboxItemAttribute(false)]
    [Guid("2c17d464-3e67-4f0b-bc4f-143e9f0f99e6")]
    public class TelerikGridWebPart : Microsoft.SharePoint.WebPartPages.WebPart
    {
        private const string ASCX_PATH = @"~/_CONTROLTEMPLATES/PS.WebParts.Rollup.Custom/TelerikGridUserControl.ascx";

        private bool _error = false;

        protected PSTelerikSkin productsBy;

        [Personalizable(PersonalizationScope.Shared), WebBrowsable, WebDisplayName("Grid Theme"), WebDescription("Use this property to select the colors and style of the grid")]
        [System.ComponentModel.Category("Appearance")]
        public PSTelerikSkin GridSkin
        {

            get { return productsBy; }

            set
            {
                productsBy = value;
                if (this.telerikGrid != null)
                    this.telerikGrid.SetGridSkin(value.ToString());
            }
        }

        private bool showToolbar = true;
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Rollup")]
        [WebDisplayName("Show 'Group By' toolbar")]
        [WebDescription("Property to display the toolbar with buttons to automatically group by columns.")]
        public bool ShowToolbar
        {
            get { return showToolbar; }
            set
            {
                showToolbar = value; 
                EnsureChildControls();
                if (telerikGrid != null)
                    telerikGrid.SetMenuVisible(value);
            }
        }

        private string _myProperty = null;

        private int pageSize = 10;

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Rollup")]
        [WebDisplayName("Page Size")]
        [WebDescription("")]
        public int PageSize
        {
            get { return pageSize; }
            set { pageSize = value; if (this.telerikGrid != null) telerikGrid.SetPageSize(value); }
        }

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Rollup")]
        [WebDisplayName("Data Source Url")]
        [WebDescription("Url of the xml data source (from rollup webpart).")]
        public string DataSourceURL
        {
            get
            {
                if (_myProperty == null)
                {
                    _myProperty = string.Empty;
                }
                return _myProperty;
            }
            set
            {
                _myProperty = value;
            }

        }

        private string groupField = string.Empty;

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Rollup")]
        [WebDisplayName("Predefined Grouping Column Name")]
        [WebDescription("Url of the xml data source (from rollup webpart).")]
        public string GroupField
        {
            get
            {
                if (groupField == null)
                {
                    groupField = string.Empty;
                }
                return groupField;
            }
            set
            {
                groupField = value;
                EnsureChildControls();
                if (telerikGrid != null)
                    telerikGrid.SetPresetGrouping(groupField, true);
            }

        }

        private string _columnInfoList;

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(false)]
        public string ColumnInfoList
        {
            get { return _columnInfoList; }
            set
            {
                _columnInfoList = value;
                if (telerikGrid != null)
                {
                    telerikGrid.Reload();
                }
            }
        }


        private TelerikGridUserControl telerikGrid = null;

        public TelerikGridWebPart()
        {
        }

        public override ToolPart[] GetToolParts()
        {
            var toolParts = new List<ToolPart>(base.GetToolParts());
            var toolpart = new TelerikGridToolPart(this);

            toolpart.Title = "Data Rollup Properties";

            toolParts.Add(toolpart);

            return toolParts.ToArray();
        }

        /// <summary>
        /// Create all your controls here for rendering.
        /// Try to avoid using the RenderWebPart() method.
        /// </summary>
        protected override void CreateChildControls()
        {
            if (!_error)
            {
                try
                {
                    base.Controls.Clear();

                    base.CreateChildControls();

                    Control control = this.Page.LoadControl(ASCX_PATH);

                    if (control is TelerikGridUserControl) telerikGrid = (TelerikGridUserControl)control;

                    telerikGrid.WebPart = this;

                    SetUserControlProperties();

                    Controls.Add(control);
                }
                catch (Exception ex)
                {
                    HandleException(ex);
                }
            }
        }

        void SetUserControlProperties()
        {
            telerikGrid.SetMenuVisible(showToolbar);

            telerikGrid.SetPageSize(this.PageSize);

            telerikGrid.SetGridSkin(this.GridSkin.ToString());

            telerikGrid.SetPresetGrouping(this.GroupField, false);

            if (!showToolbar && string.IsNullOrEmpty(GroupField)) telerikGrid.SetMenuVisible(showToolbar);
        }

        protected override void OnPreRender(EventArgs e)
        {
            if (telerikGrid != null && !String.IsNullOrEmpty((DataSourceURL)))
            {
                if (reLoad || !Page.IsPostBack)
                {
                    SetUserControlProperties();

                    this.telerikGrid.Reload();

                    reLoad = false;
                }
            }

            base.OnPreRender(e);
        }

        /// <summary>
        /// Ensures that the CreateChildControls() is called before events.
        /// Use CreateChildControls() to create your controls.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            if (!_error)
            {
                try
                {
                    base.OnLoad(e);

                    this.EnsureChildControls();

                    // Your code here...
                }
                catch (Exception ex)
                {
                    HandleException(ex);
                }
            }
        }

        /// <summary>
        /// Clear all child controls and add an error message for display.
        /// </summary>
        /// <param name="ex"></param>
        private void HandleException(Exception ex)
        {
            this._error = true;

            this.Controls.Clear();

            this.Controls.Add(new LiteralControl(ex.Message));
        }

        internal DataSet GetRawData()
        {
            Uri dsUrl;

            var dataSet = new DataSet();

            if (!String.IsNullOrEmpty(DataSourceURL))
            {
                var memoryStream = new MemoryStream();

                if (Uri.TryCreate(this.DataSourceURL, UriKind.RelativeOrAbsolute, out dsUrl))
                {
                    using (WebClient webClient = new WebClient())
                    {
                        webClient.UseDefaultCredentials = true;

                        var bytes = webClient.DownloadData(DataSourceURL);

                        memoryStream = new MemoryStream(bytes);
                    }
                }
                else
                {
                    try
                    {
                        var fileName = "/_layouts/PS.WebParts.Rollup.Custom/sample.xml";

                        fileName = DataSourceURL;

                        var file = Page.Server.MapPath(fileName);

                        memoryStream = new MemoryStream(File.ReadAllBytes(file));
                    }
                    catch (Exception ex)
                    {

                    }
                }

                try
                {
                    dataSet.ReadXml(memoryStream);
                }
                catch (Exception)
                {
                }
            }
            else
            {
                var table = dataSet.Tables.Add("Rows");

                table.Columns.Add("Message");

                table.NewRow()["Message"] = "There are no records in this view";

                dataSet.AcceptChanges();
            }

            //dataSet = CleanLookups(dataSet);

            return dataSet;
        }

        private static DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(RollupColumnInfo[]));

        public List<RollupColumnInfo> GetColumnInfo(DataSet set)
        {
            var columnInfo = TelerikGridWebPart.GetValue(ColumnInfoList);

            columnInfo = ValidateColumnsInfo(set, columnInfo);

            return columnInfo;
        }

        public List<RollupColumnInfo> GetColumnInfo()
        {
            var dataSet = GetRawData();
            return GetColumnInfo(dataSet);
        }

        private static List<RollupColumnInfo> GetValue(string val)
        {
            if (!string.IsNullOrEmpty(val))
            {
                var bytes = Encoding.ASCII.GetBytes(val);

                var obj = serializer.ReadObject(new MemoryStream(bytes));

                if (obj is RollupColumnInfo[])
                {
                    return new List<RollupColumnInfo>((RollupColumnInfo[])obj);
                }
            }
            return null;
        }

        private static List<RollupColumnInfo> ValidateColumnsInfo(DataSet rawDataSet, List<RollupColumnInfo> currentColumnInfo)
        {
            #region Get Columns from Data

            var table = rawDataSet.Tables[0];

            var columnsFromData = new List<string>();

            if (table.Rows.Count > 0)
            {
                foreach (DataColumn column in table.Columns)
                {
                    if (!columnsFromData.Contains(column.ColumnName)) columnsFromData.Add(column.ColumnName);
                }
            }
            #endregion

            var existingInfo = currentColumnInfo;// TelerikGridWebPart.GetValue(telerikGridWebPart.ColumnInfoList);

            if (existingInfo == null) existingInfo = new List<RollupColumnInfo>();

            if (columnsFromData.Count > 0)
            {
                foreach (string columnName in columnsFromData)
                {
                    var col = existingInfo.FirstOrDefault(i => i.Name == columnName);

                    if (col == null)
                        existingInfo.Add(new RollupColumnInfo()
                                             {
                                                 ColType = "Text",
                                                 Header = columnName,
                                                 Hidden = "false",
                                                 Name = columnName,
                                                 //LinkPattern = columnName,
                                                 LinkSources = new KeyValuePair<string, string>[0],
                                                 //TextPattern = columnName
                                                 Order = 0
                                             });
                }

                existingInfo.Where(f => !columnsFromData.Contains(f.Name)).ToList().ForEach(i => existingInfo.Remove(i));

                foreach (RollupColumnInfo info in existingInfo)
                {
                    info.LinkSources = ValidateSelectedColumns(info.LinkSources, existingInfo);
                    info.TextSources = ValidateSelectedColumns(info.TextSources, existingInfo);
                }
            }

            return existingInfo;
        }

        private static KeyValuePair<string, string>[] ValidateSelectedColumns(KeyValuePair<string, string>[] selected, List<RollupColumnInfo> available)
        {
            var dic = new Dictionary<string, string>();

            if (selected != null)
                dic = selected.ToDictionary(k => k.Key, v => v.Value);

            string[] keys = new string[dic.Keys.Count];

            dic.Keys.CopyTo(keys, 0);

            foreach (var key in keys)
            {
                if (available.FirstOrDefault(f => f.Name == key) == null)
                    dic.Remove(key);
            }

            foreach (RollupColumnInfo j in available)
            {
                if (!dic.ContainsKey(j.Name)) dic.Add(j.Name, "0");
            }
            return dic.ToArray();
        }

        private bool reLoad = false;

        internal void ReBindControl()
        {
            reLoad = true;
        }
    }

    public enum PSTelerikSkin
    {
        Default,
        Black,
        Forest,
        Gray,
        Hay,
        //Inox,
        [Description("Office 2007")]
        Office2007, Outlook,
        //SkyBlue, 
        Sunset, Telerik, Vista, Web20, WebBlue
    }
}
